﻿using System;
using System.Net.Mail;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using BLL.Workers;
using BLL.Workflows;
using DO.Workflows;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Timer=DO.Workflows.Timer;

namespace Test.Workflows
{
    /// <summary>
    /// Summary description for WorkflowServiceTest
    /// </summary>
    [TestClass]
    public class WorkflowServiceTest
    {
        private const string ScheduledWorkflowName = "Test scheduled workflow";
        private const string ManualStartWorkflowName = "Manual started workflow";

        public WorkflowServiceTest()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        [TestMethod]
        public void TestPublishScheduledWorkflow()
        {
            
            Timer timer=new Timer();
            timer.Instruction =
                new TimerInstruction
                    {
                        IsActive=true,
                        ActivatedOn=DateTime.Now,
                        ComponentID=timer.ComponentID,
                        JobTicketID = Guid.Empty,
                        LastRunTime=null,
                        NextRunTime=null,
                        Span = TimeSpan.FromDays(1),
                        SubmitTime=DateTime.Now
                    };
            timer.Output = new TimerOutput
                               {
                                   ComponentID = timer.ComponentID,
                                   FinishTime = null,
                                   JobID = Guid.Empty
                               };

            EmailComponent email = this.CreateDefaultEmailComponent();

            WorkflowDesign wfDesign =
                new WorkflowDesign
                {
                    Author = Environment.UserName,
                    Components = new Dictionary<Guid, WorkflowComponentBase>(),
                    CreatedOn = DateTime.Now,
                    FailureConnectors = new Dictionary<Guid, List<Guid>>(),
                    FileName = ScheduledWorkflowName + ".wox",
                    WorkflowName = ScheduledWorkflowName,
                    ModifiedOn = DateTime.Now,
                    SuccessConnectors = new Dictionary<Guid, List<Guid>>(),
                    Version = new Version(1, 0),
                    WorkflowID = Guid.NewGuid()
                };
            wfDesign.Components.Add(timer.ComponentID,timer);
            wfDesign.Components.Add(email.ComponentID,email);
            List<Guid> downstreamComponentIDs=new List<Guid>();
            downstreamComponentIDs.Add(email.ComponentID);
            wfDesign.SuccessConnectors.Add(timer.ComponentID,downstreamComponentIDs);

            WorkflowManager.SaveWorkflow(wfDesign);

            WorkflowDesign savedWorkflow = WorkflowManager.GetWorkflowByName(ScheduledWorkflowName);
            Assert.AreEqual(wfDesign.WorkflowID, savedWorkflow.WorkflowID);
        }

        [TestMethod]
        public void TestPublishManualStartWorkflow()
        {
            ManualStart manualStart=new ManualStart();
            manualStart.Instruction =
                new ManualStartInstruction
                {
                    IsActive = true,
                    ActivatedOn = DateTime.Now,
                    ComponentID = manualStart.ComponentID,
                    JobTicketID = Guid.Empty,
                    LastRunTime = null,
                    NextRunTime = null,
                    Span = TimeSpan.FromDays(1),
                    SubmitTime = DateTime.Now
                };
            manualStart.Output = new ManualStartOutput
            {
                ComponentID = manualStart.ComponentID,
                FinishTime = null,
                JobID = Guid.Empty
            };

            EmailComponent email = this.CreateDefaultEmailComponent();

            WorkflowDesign wfDesign =
                new WorkflowDesign
                {
                    Author = Environment.UserName,
                    Components = new Dictionary<Guid, WorkflowComponentBase>(),
                    CreatedOn = DateTime.Now,
                    FailureConnectors = new Dictionary<Guid, List<Guid>>(),
                    FileName = ManualStartWorkflowName+".wox",
                    WorkflowName = ManualStartWorkflowName,
                    ModifiedOn = DateTime.Now,
                    SuccessConnectors = new Dictionary<Guid, List<Guid>>(),
                    Version = new Version(1, 0),
                    WorkflowID = Guid.NewGuid()
                };
            wfDesign.Components.Add(manualStart.ComponentID, manualStart);
            wfDesign.Components.Add(email.ComponentID, email);
            List<Guid> downstreamComponentIDs = new List<Guid>();
            downstreamComponentIDs.Add(email.ComponentID);
            wfDesign.SuccessConnectors.Add(manualStart.ComponentID, downstreamComponentIDs);

            WorkflowManager.SaveWorkflow(wfDesign);

            WorkflowDesign savedWorkflow = WorkflowManager.GetWorkflowByName(ManualStartWorkflowName);
            Assert.AreEqual(wfDesign.WorkflowID, savedWorkflow.WorkflowID);
        }

        [TestMethod]
        public void TestScheduledWorkflow()
        {
            //string xml = WorkflowManager.GetWorkflowByName(ScheduledWorkflowName);
            //WorkflowDesign wfDesign = WorkflowDesign.Read(xml);
            //ManualWorkflowAgent agent=new ManualWorkflowAgent(wfDesign);
            //agent.Run();
            DateTime startTime = DateTime.Now;
            WorkflowService workflowSvc = new WorkflowService();
            workflowSvc.RetrievalInterval = 1000 * 15;
            workflowSvc.Start();
            Thread.Sleep(1000 * 60 * 4); // 4 min 
            workflowSvc.Stop();
            WorkflowDesign wfDesign = WorkflowManager.GetWorkflowByName(ScheduledWorkflowName);
            List<Run> runs = WorkflowManager.GetWorkflowRuns(wfDesign.WorkflowID);
            bool hasNewRun = false;
            foreach(Run run in runs)
            {
                if (run.SubmitTime != null || run.SubmitTime > startTime)
                {
                    hasNewRun = true;
                    break;
                }
            }
            if(!hasNewRun)
                Assert.Fail("Unable to create run after 1 min");
        }

        #region default components
        private EmailComponent CreateDefaultEmailComponent()
        {
            EmailComponent email = new EmailComponent();
            email.Instruction =
                new EmailInstruction
                {
                    Attachments = new List<string>(),
                    Body = "Done",
                    ComponentID = email.ComponentID,
                    EnableSSL = true,
                    SmtpPort = 587,
                    FromAddress = "li.xiaodong@biosoftworks.com",
                    ToAddress = "li.xiaodong@biosoftworks.com",
                    JobTicketID = Guid.Empty,
                    Password = "lingling",
                    RequireAuthentication = true,
                    SmtpServer = "smtp.gmail.com",
                    Subject = "Workflow done",
                    UserName = "xdling",
                    UseOutlook = false,
                    CC = "",
                    Priority = MailPriority.High
                };
            email.Output =
                new EmailOutput
                {
                    ComponentID = email.ComponentID,
                    FinishTime = null,
                    JobID = Guid.Empty
                };
            return email;
        }
        #endregion
    }
}
